import midi
import pickle

__CONFIG__ = None

class Configuration(object):
    def __init__(self):
        self.namespace = {}

    def newns(self, ns):
        self.namespace[ns] = {}

    def getns(self, nsname='__default__'):
        return self.namespace[nsname]
    __getitem__ = getns

    def setns(self, ns, nsname='__default__'):
        self.namespace[nsname] = ns
        
    def updatens(self, ns, nsname='__default__'):
        self.namespace[nsname].update(ns) 
        
    def setvar(self, var, value, ns='__default__'):
        self.namespace[nsname][var] = value

    def getvar(self, var, nsname='__default__'):
        return self.namespace[nsname][var]

    def save(self, fn):
        f = open(fn, "w")
        pickle.dump(self.namespace, f)
        f.close()

    def load(self, fn):
        f = open(fn)
        nss = pickle.load(f)
        f.close()
        for ns in nss:
            self.updatens(nss[ns], ns)

    # quick and dirty Singleton
    def get_instance(cls):
        global __CONFIG__
        if __CONFIG__ == None:
            __CONFIG__ = cls()
        return __CONFIG__
    get_instance = classmethod(get_instance)


class EnsembleRobot(object):
    _defaults = {}
    _config = None

    class __metaclass__(type):
        def __init__(cls, name, bases, dict):
            if name not in ['EnsembleRobot']:
                cls._config = Configuration.get_instance()
                cls._config.setns(cls._defaults, name.lower())

    def __init__(self):
        self._init()

    def _init(self):
        ns = self.__class__.__name__.lower()
        self.__dict__.update(self._config.getns(ns))
        self.init()

    def init(self):
        pass

    def _new_note_on(self, pitch, velocity, tick, channel=0):
        noteon = midi.NoteOnEvent()
        noteon.channel = channel
        noteon.tick = tick
        noteon.pitch = pitch
        noteon.velocity = velocity
        return noteon

    def _new_note_off(self, pitch, tick, channel=0):
        noteoff = midi.NoteOffEvent()
        noteoff.channel = channel
        noteoff.tick = tick
        noteoff.pitch = pitch
        noteoff.velocity = 0
        return noteoff

    def _copy_note_event(self, event, on=True, channel=0):
        if on:
            outev = NoteOnMidiEvent(event)
        else:
            outev = NoteOffMidiEvent(event)
        outev.channel = channel
        outev.msdelay = event.msdelay
        outev.tick = event.tick
        outev.pitch = event.pitch
        outev.velocity = event.velocity

    def _new_note_pair(self, pitch, velocity, ontick, offtick, stream):
        noteon = self._new_note_on(pitch, velocity, ontick)
        stream.add_event(noteon)
        noteoff = self._new_note_off(pitch, offtick)
        stream.add_event(noteoff)

    def light(self, pitch, velocity, tick, stream):
        pass
    
    def note(self, pitch, velocity, tick, stream):
        pass
